home *** CD-ROM | disk | FTP | other *** search
- Unit Clock;
- {
- Author: Trevor J Carlsen
- Purpose: Demonstrate a simple "on screen" clock.
-
- This demo Unit works by "hooking" the timer interrupt ($1c). This
- interrupt is called by the hardware interrupt ($08) approximately 18.2
- times every second and normally consists of a simple return instruction
- unless some other application has already hooked it.
-
- Because the routine is called roughly 18 times every second it is
- important that any processing it contains is optimised as much as
- possible. Obviously the best way to do this is by assembly language but
- in this demo I have used almost pure Turbo Pascal and have set up a
- counter Variable and any processing is only done every 6 calls. This is
- more than sufficient and minimises processing. The routine is by no
- means perfect - there will be a minor irregularity For the final 10
- seconds of each day and For about half a second each hour. Better this
- than to waste valuable processing time in the interrupt by coding it
- out.
-
- Because Dos is not re-entrant it is also important that the routine make
- no calls to any Procedure or Function that makes use of Dos For its
- operation. Thus no Writeln, Write can be used. To display the time on
- screen an Array is addressed directly to screen memory. Any changes in
- this Array are thus reflected on the screen. The downside to this is
- that on older CGAs this would cause a "snow" effect and code would be
- needed to eliminate this. It also means that the TP Procedure GetTime
- cannot be used. So the time is calculated from the value stored at the
- clock tick counter location.
-
- To display an on-screen clock all that is required is For a Programmer
- to include this Unit in the Uses declaration of the Program.}
-
- Interface
-
- Const
- DisplayClock : Boolean = True;
-
- Implementation
- { Everything is private to this Unit }
-
- Uses Dos;
-
- Const
- line = 0; { Change as required For position of display on screen }
- column = 72; { Top left corner is 0,0 }
- ScreenPos = (line * 160) + (column * 2);
- Colour = $1f; { White on Blue }
- ZeroChar = Colour shl 8 + ord('0');
- Colon = Colour shl 8 + ord(':');
- Type
- timestr = Array[0..7] of Word;
- timeptr = ^timestr;
- Var
- time : timeptr;
- OldInt1c : Pointer;
- ExitSave : Pointer;
-
- {$F+}
- Procedure Int1cISR; interrupt;
- { This will be called every clock tick by hardware interrupt $08 }
- Const
- count : Integer = 0; { To keep track of our calls }
- Var
- hr : Word Absolute $40:$6e;
- ticks : Word Absolute $40:$6c;
- { This location keeps the number of clock ticks since 00:00}
- min,
- sec : Byte;
- seconds : Word;
- begin
- Asm cli end;
- if DisplayClock then begin
- inc(count);
- if count = 6 then { ticks to update the display } begin
- count := 0; { equality check and assignment faster than mod 9 }
- seconds := ticks * LongInt(10) div 182; { speed = no Reals }
- min := (seconds div 60) mod 60;
- sec := seconds mod 60;
-
- { The following statements are what actually display the on-screen time}
-
- time^[0] := ZeroChar + (hr div 10); { first Char of hours }
- time^[1] := ZeroChar + (hr mod 10); { second Char of hours }
- time^[2] := Colon;
- time^[3] := ZeroChar + (min div 10); { first Char of minutes }
- time^[4] := ZeroChar + (min mod 10); { second Char of minutes }
- time^[5] := Colon;
- time^[6] := ZeroChar + (sec div 10); { first Char of seconds }
- time^[7] := ZeroChar + (sec mod 10); { second Char of seconds }
- end; { if count = 6 }
- end; { if DisplayClock }
- Asm
- sti
- pushf { push flags to set up For IRET }
- call OldInt1c; { Call old ISR entry point }
- end;
- end; { Int1cISR }
-
- Procedure ClockExitProc;
- { This Procedure is VERY important as you have hooked the timer interrupt }
- { and therefore if this is omitted when the Unit is terminated your }
- { system will crash in an unpredictable and possibly damaging way. }
- begin
- ExitProc := ExitSave;
- SetIntVec($1c,OldInt1c); { This "unhooks" the timer vector }
- end;
- {$F-}
-
- Procedure Initialise;
- Var
- mode : Byte Absolute $40:$49;
- begin
- if mode = 7 then { must be a mono adaptor }
- time := ptr($b000,ScreenPos)
- else { colour adaptor of some kind }
- time := ptr($b800,ScreenPos);
- GetIntVec($1c,OldInt1c); { Get old timer vector and save it }
- ExitSave := ExitProc; { Save old Exit Procedure }
- ExitProc := @ClockExitProc; { Setup a new Exit Procedure }
- SetIntVec($1c,@Int1cISR); { Hook the timer vector to the new Procedure }
- end; { Initialise }
-
- begin
- Initialise;
- end.
-